﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Collections.Concurrent;
namespace Janus.Cores.Tools
{
    /// <summary>
    /// 反射函数处理
    /// </summary>
    public static class RelfHelper
    {
        static ConcurrentDictionary<string, RuntimeMethodHandle[]> __cacheTypeProperties =
            new ConcurrentDictionary<string,RuntimeMethodHandle[]>();

        /// <summary>
        /// 设置对象的一个属性
        /// </summary>
        /// <param name="obj">对象实例</param>
        /// <param name="property">属性名称</param>
        /// <param name="value">值</param>
        public static void SetValue(object obj,string property,object value)
        {
            if (obj == null)
                return;
            var mi = GetPropertyMethod(obj.GetType(), property, false);
            if (mi == null)
                throw new ArgumentOutOfRangeException("没有在对象上找到对应的属性：" + property);
            mi.Invoke(obj,new object[]{ value });
        }

        /// <summary>
        /// 获取对象的一个属性值
        /// </summary>
        /// <param name="obj">对象实例</param>
        /// <param name="property">属性名称</param>
        /// <returns>属性值</returns>
        public static object GetValue(object obj, string property)
        {
            if (obj == null)
                return null;
            var mi = GetPropertyMethod(obj.GetType(), property, true);
            if (mi == null)
                throw new ArgumentOutOfRangeException("没有在对象上找到对应的属性：" + property);
            return mi.Invoke(obj,null);
        }

        private static MethodBase GetPropertyMethod(Type type,string property,bool get )
        {
            var handler = type.TypeHandle;
            string key = string.Format("{0}.{1}", type.FullName, property);
            RuntimeMethodHandle[] items;
            if (!__cacheTypeProperties.TryGetValue(key, out items))
            {
                lock (type.FullName)
                {
                    LoadTypePropertiesInfo(type);
                }
                items = __cacheTypeProperties[key];
            }
            if( get)
                return MethodInfo.GetMethodFromHandle(items[0]);    
            else
                return MethodInfo.GetMethodFromHandle(items[1]);    
        }

        private static void LoadTypePropertiesInfo(Type type)
        {
            
            var properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
            foreach (var item in properties)
            {
                var tuple = new RuntimeMethodHandle[2];
                if( item.CanRead )
                    tuple[0] = item.GetGetMethod().MethodHandle;

                if (item.CanWrite)
                    tuple[1] = item.GetSetMethod().MethodHandle;

                __cacheTypeProperties.TryAdd(string.Format("{0}.{1}", type.FullName, item.Name), tuple);
            }
           
        }
        

    }
}
